# 功能模块：工厂场景
# 作者：dl
# 描述：工厂场景

import os
import platform
import asyncio
from trame.app import asynchronous
from gltf import GLTFLoader, GLTFRenderEngine
import vtk
from visualizationCom.tools.color import hex_to_rgba

from vtkmodules.vtkCommonColor import vtkNamedColors
from vtkmodules.vtkRenderingOpenGL2 import (
    vtkCameraPass,
    vtkRenderPassCollection,
    vtkSequencePass,
    vtkShadowMapPass
)
from vtkmodules.vtkFiltersSources import vtkCubeSource
from vtkmodules.vtkRenderingCore import (
    vtkLight,
    vtkActor,
    vtkPolyDataMapper,
    vtkLightActor
)
import datetime

class factoryScene:
    # 构造函数
    def __init__(self, parent, webState, webCtrl):
        self.parent = parent
        self.webState = webState
        self.webCtrl = webCtrl

        # 工厂场景相关属性
        self.hasLoadScene = False  # 用于判断是否存在缓存
        # self.renderer = GLTFRenderer()
        self.engine = GLTFRenderEngine()
        self.renderer = self.engine.GetDefaultRenderer()
        self.camera = self.engine.GetCamera()

        # 临时解决renderer自带光源因为角度照不到的问题
        self.renderer.CreateLight()

        bg_color = hex_to_rgba('#132c4a')
        self.renderer.SetBackground(bg_color[0], bg_color[1], bg_color[2])

        # 定义相机初始化位置，用于重置
        self.initial_position = 0
        self.initial_focal_point = 0
        self.initial_view_up = 0

        self.sceneList = []

        # 漫游相机功能
        self.cameraAnimation = False
        self.animationStartTime = datetime.datetime.now()
        self.animationLastUpdate = datetime.datetime.now()

    def enterScene(self):

        self.parent.mouseInteractorEvent.outline.Clear()
        self.parent.mouseInteractorEvent.lastPick = None

        self.renderer.SetActiveCamera(self.camera)

        with self.webState:
            self.webState.sceneKey = 'factory'

        self.parent.currentRenderer = self.renderer

        # 暂时写死模型
        if self.hasLoadScene == False:
            camera = self.camera
            self.initial_position = camera.GetPosition()
            self.initial_focal_point = camera.GetFocalPoint()
            self.initial_view_up = camera.GetViewUp()

            CURRENT_DIRECTORY = os.path.dirname(
                os.path.dirname(os.path.dirname(__file__)))

            user_input = "model/factory/factory.gltf"

            # 结合 CURRENT_DIRECTORY 和 user_input 形成新的地址
            new_directory = os.path.join(CURRENT_DIRECTORY, user_input)
            self.load_file(new_directory)

        self.hasLoadScene = True

        self.parent.renderWindow.AddRenderer(self.renderer)
        # 重置交互器
        self.engine.SetRenderWindow(self.parent.renderWindow)
        self.parent.mouseInteractorEvent.SetDefaultRenderer(self.renderer)
        self.parent.mouseInteractorEvent.SetOutlineRenderer(
            self.engine.GetOutlineRenderer())

        # 添加阴影会导致无法精准拾取
        # self.setShadows()

        self.restCamera()
        self.parent.renderWindow.Render()
        self.webCtrl.view_update()

        self.add3DText()
        self.playRoamView()
        self.webCtrl.sendMsgToParent({"eventScene":"factory","eventName":"enterScene","value":"complete"})

    def leaveScene(self):
        self.cameraAnimation = False
        highlight = self.engine.GetHighlightRenderer()
        highlight.Clear()
        self.parent.renderWindow.RemoveRenderer(self.renderer)
        # self.webCtrl.view_update()

    def highlight_scene(self, index):

        scene = self.sceneList[index]
        # highlight = self.engine.GetHighlightRenderer()
        # highlight.AddScene(scene)
        self.engine.Highlight(scene, None, color=[1, 0, 0], opacity=1)
        self.webCtrl.view_update()

    def restCamera(self):
        # 获取当前相机
        camera = self.renderer.GetActiveCamera()

        # 重置相机的位置和方向为初始状态
        camera.SetPosition(self.initial_position)
        camera.SetFocalPoint(self.initial_focal_point)
        camera.SetViewUp(self.initial_view_up)
        self.renderer.ResetCamera()

    def changeEvn(self,bgIndex):
        if bgIndex == 1:
            # CURRENT_DIRECTORY = os.path.dirname(
            #     os.path.dirname(os.path.dirname(__file__)))

            # modePath = "3dENV/spaichingen_hill_1k.hdr"

            # # 结合 CURRENT_DIRECTORY 和 modePath 形成新的地址
            # new_directory = os.path.join(CURRENT_DIRECTORY, modePath)
            # self.renderer.SetEnvmap(new_directory)
            bg_color = hex_to_rgba('#041A21')
            self.renderer.SetBackground(bg_color[0], bg_color[1], bg_color[2])
        else:
            bg_color = hex_to_rgba('#132c4a')
            self.renderer.SetBackground(bg_color[0], bg_color[1], bg_color[2])
        self.parent.renderWindow.Render()
        self.webCtrl.view_update()
        self.webCtrl.view_update()

        self.webCtrl.sendMsgToParent({"eventScene":"factory","eventName":"enterScene","value":"complete"})

    def setShadows(self):

        # 设置阴影
        colors = vtkNamedColors()
        # Color temp. 5400°K
        colors.SetColor('HighNoonSun', [255, 255, 251, 255])
        # Color temp. 2850°K
        colors.SetColor('100W Tungsten', [255, 214, 170, 255])
        light2 = vtkLight()
        light2.SetFocalPoint(0, 0, 0)
        light2.SetPosition(3.0, 6.0, 6.0)
        light2.SetColor(colors.GetColor3d('100W Tungsten'))
        light2.SetIntensity(0.8)
        self.renderer.AddLight(light2)

        angle = light2.GetConeAngle()
        if light2.LightTypeIsSceneLight() and light2.GetPositional() and angle < 180.0:  # spotlight
            la = vtkLightActor()
            la.SetLight(light2)
            self.renderer.AddViewProp(la)

        bounds = [-30, 30, -30, 30, -30, 30]
        rnge = [0] * 3
        rnge[0] = bounds[1] - bounds[0]
        rnge[1] = bounds[3] - bounds[2]
        rnge[2] = bounds[5] - bounds[4]
        print('range: ', ', '.join(['{0:0.6f}'.format(i) for i in rnge]))
        expand = 1.0

        plane = vtkCubeSource()
        plane.SetCenter((bounds[1] + bounds[0]) / 2.0,
                        0,
                        (bounds[5] + bounds[4]) / 2.0)
        plane.SetXLength(bounds[1] - bounds[0] + (rnge[0] * expand))
        plane.SetYLength(1)
        plane.SetZLength(bounds[5] - bounds[4] + (rnge[2] * expand))

        planeMapper = vtkPolyDataMapper()
        planeMapper.SetInputConnection(plane.GetOutputPort())

        planeActor = vtkActor()
        planeActor.SetMapper(planeMapper)
        self.renderer.AddActor(planeActor)

        shadows = vtkShadowMapPass()

        seq = vtkSequencePass()

        passes = vtkRenderPassCollection()
        passes.AddItem(shadows.GetShadowMapBakerPass())
        passes.AddItem(shadows)
        seq.SetPasses(passes)

        cameraP = vtkCameraPass()
        cameraP.SetDelegatePass(seq)

        self.renderer.SetPass(cameraP)
        self.renderer.SetBackground(colors.GetColor3d('Silver'))

    def load_file(self, file_name):
        self.renderer.RemoveAllViewProps()

        self.reader_detail = GLTFLoader()
        self.reader_detail.Load(file_name)
        self.renderer.AddScene(self.reader_detail.GetScene())

        self.sceneList.append(self.reader_detail.GetScene())

        self.reader_detail_two = GLTFLoader()
        self.reader_detail_two.Load(file_name)
        scene_two = self.reader_detail_two.GetScene()
        scene_two.transform.Translate(100, 0, 0)
        self.renderer.AddScene(scene_two)

        self.sceneList.append(scene_two)

        self.reader_detail_three = GLTFLoader()
        self.reader_detail_three.Load(file_name)
        scene_three = self.reader_detail_two.GetScene()
        scene_three.transform.Translate(-100, 0, 0)
        self.renderer.AddScene(scene_three)

        self.sceneList.append(scene_three)

    def add3DText(self):
        # 设置中文字体文件路径
        CURRENT_DIRECTORY = os.path.dirname(
            os.path.dirname(os.path.dirname(__file__)))

        user_input = "font/"

        self.textActor = vtk.vtkTextActor3D()
        self.textActor.SetInput("车间1")  # 设置中文文字 换行格式 设备故障\n2023-12-26

        # 使用FreeType字体库和字符纹理映射
        textProperty = self.textActor.GetTextProperty()
        textProperty.SetFontFamily(vtk.VTK_FONT_FILE)  # 设置字体为FreeType字体库

        # 结合 CURRENT_DIRECTORY 和 user_input 形成新的地址
        new_directory = os.path.join(CURRENT_DIRECTORY, user_input)
        textProperty.SetFontFile(
            new_directory + "sanjizihaisonggbk.ttf")

        self.textActor.GetTextProperty().SetColor(1, 1, 1)  # 设置文字颜色为白色
        self.textActor.GetTextProperty().SetFontSize(18)  # 设置文字大小
        self.textActor.SetScale(0.5)
        self.textActor.SetPosition(12, 42, 0.01)

        # 文字2
        self.textActor_2 = vtk.vtkTextActor3D()
        self.textActor_2.SetInput("车间2")  # 设置中文文字 换行格式 设备故障\n2023-12-26

        # 使用FreeType字体库和字符纹理映射
        textProperty_2 = self.textActor_2.GetTextProperty()
        textProperty_2.SetFontFamily(vtk.VTK_FONT_FILE)  # 设置字体为FreeType字体库

        textProperty_2.SetFontFile(
            new_directory + "sanjizihaisonggbk.ttf")

        self.textActor_2.GetTextProperty().SetColor(1, 1, 1)  # 设置文字颜色为白色
        self.textActor_2.GetTextProperty().SetFontSize(18)  # 设置文字大小
        self.textActor_2.SetScale(0.5)
        self.textActor_2.SetPosition(-95, 42, 0.01)

        # 文字3
        self.textActor_3 = vtk.vtkTextActor3D()
        self.textActor_3.SetInput("车间3")  # 设置中文文字 换行格式 设备故障\n2023-12-26

        # 使用FreeType字体库和字符纹理映射
        textProperty_3 = self.textActor_3.GetTextProperty()
        textProperty_3.SetFontFamily(vtk.VTK_FONT_FILE)  # 设置字体为FreeType字体库

        textProperty_3.SetFontFile(
            new_directory + "sanjizihaisonggbk.ttf")

        self.textActor_3.GetTextProperty().SetColor(1, 1, 1)  # 设置文字颜色为白色
        self.textActor_3.GetTextProperty().SetFontSize(18)  # 设置文字大小
        self.textActor_3.SetScale(0.5)
        self.textActor_3.SetPosition(112, 42, 0.01)

        # 读入图像数据
        user_input = "images/"

        # 结合 CURRENT_DIRECTORY 和 user_input 形成新的地址
        new_directory = os.path.join(CURRENT_DIRECTORY, user_input)
        reader = vtk.vtkPNGReader()
        reader.SetFileName(new_directory + "dialogbox_new.png")
        reader.Update()

        # 创建图像显示对象
        self.imageActor_dialogbox = vtk.vtkImageActor()
        self.imageActor_dialogbox.SetInputData(reader.GetOutput())
        self.imageActor_dialogbox.SetPosition(3, 23, 0)
        self.imageActor_dialogbox.SetScale(0.2)
        self.imageActor_dialogbox.SetOpacity(0.7)

        self.renderer.AddActor(self.imageActor_dialogbox)
        self.renderer.AddActor(self.textActor)

        # 创建图像显示对象2
        self.imageActor_dialogbox_2 = vtk.vtkImageActor()
        self.imageActor_dialogbox_2.SetInputData(reader.GetOutput())
        self.imageActor_dialogbox_2.SetPosition(-103, 23, 0)
        self.imageActor_dialogbox_2.SetScale(0.2)
        self.imageActor_dialogbox_2.SetOpacity(0.7)

        self.renderer.AddActor(self.imageActor_dialogbox_2)
        self.renderer.AddActor(self.textActor_2)

        # 创建图像显示对象3
        self.imageActor_dialogbox_3 = vtk.vtkImageActor()
        self.imageActor_dialogbox_3.SetInputData(reader.GetOutput())
        self.imageActor_dialogbox_3.SetPosition(103, 23, 0)
        self.imageActor_dialogbox_3.SetScale(0.2)
        self.imageActor_dialogbox_3.SetOpacity(0.7)

        self.renderer.AddActor(self.imageActor_dialogbox_3)
        self.renderer.AddActor(self.textActor_3)

    def roamView(self):
        self.cameraAnimation = not self.cameraAnimation
        if self.cameraAnimation == True:
            self.playRoamView()

    @asynchronous.task
    async def playRoamView(self):
        # check animation
        if self.cameraAnimation == False:
            print("stop playRoamView")
            return

        print("start playRoamView")

        start = datetime.datetime.now()
        lastUpdate = start
        while self.cameraAnimation:
            now = datetime.datetime.now()        
            # minimal update interval?
            elapsed = (now - self.animationLastUpdate).total_seconds()
            if elapsed > 0.01:
                self.animationLastUpdate = now

                # camera animation
                if self.cameraAnimation:       
                    self.camera.SetViewUp(0, 1, 0)
                    self.camera.Azimuth(elapsed * 15)
                    self.webCtrl.view_update()

            lastUpdate = datetime.datetime.now()             
            while (datetime.datetime.now()-lastUpdate).total_seconds() < 0.1:
                await asyncio.sleep(0.001)

    def focus_to_pick(self):
        if self.parent.mouseInteractorEvent.lastPick:
            self.engine.GetOutlineRenderer().ResetCamera()
            self.camera.Dolly(0.5)
            self.renderer.ResetCameraClippingRange() 
            self.webCtrl.view_update()